package com.stone.databinding.ui;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.view.View;

import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import android.animation.ArgbEvaluator;
import android.view.animation.DecelerateInterpolator;

import com.stone.databinding.R;

/**
 * A collection of [BindingAdapter]s used to create animations in the app
 */
public class AnimationBindingAdapters {
    private static final long VERTICAL_BIAS_ANIMATION_DURATION = 900L;

    private static final long BG_COLOR_ANIMATION_DURATION = 500L;

    /**
     * Controls a background color animation.
     *
     * @param view one of the timers (work/rest)
     * @param timerRunning whether the app timer is running
     * @param activeStage whether this particular timer (work/rest) is active
     */
    @BindingAdapter(value={"animateBackground", "animateBackgroundStage"}, requireAll = true)
    public static void animateBackground(View view, boolean timerRunning, boolean activeStage) {
        // If the timer is not running, don't animate and set the default color.
        if (!timerRunning) {
            view.setBackgroundColor(
                    ContextCompat.getColor(view.getContext(), R.color.disabledInputColor));
            // This tag prevents a glitch going from reset to started.
            view.setTag(R.id.hasBeenAnimated, false);
            return;
        }

        // activeStage controls whether this particular timer (work or rest) is active.
        if (activeStage) {
            // Start animation
            animateBgColor(view, true);
            // This tag prevents a glitch going from paused to started.
            view.setTag(R.id.hasBeenAnimated, true);
        } else {
            // Prevent "end" animation if animation never started
            Boolean hasItBeenAnimated = (Boolean) view.getTag(R.id.hasBeenAnimated);
            if (hasItBeenAnimated) {  // this means false if null
                // End animation
                animateBgColor(view, false);
                view.setTag(R.id.hasBeenAnimated, false);
            }
        }
    }

    /**
     * Controls an animation that moves a view up and down.
     *
     * @param view one of the timers (work/rest)
     * @param timerRunning whether the app timer is running
     * @param activeStage whether this particular timer (work/rest) is active
     */
    @BindingAdapter(value={"animateVerticalBias", "animateVerticalBiasStage"},
            requireAll = true)
    public static void animateVerticalBias(View view, Boolean timerRunning, Boolean activeStage) {
        // Change the vertical bias of the View depending on the current state
        if (timerRunning && activeStage) {
            animateVerticalBias(view, 0.6f); // Workout
        } else if (timerRunning && !activeStage) {
            animateVerticalBias(view, 0.4f); // Rest;
        } else {
            animateVerticalBias(view, 0.5f); // Idle;
        }
    }

    private static void animateBgColor(View view, Boolean tint) {
        int colorRes = ContextCompat.getColor(view.getContext(), R.color.colorPrimaryLight);
        int color2Res = ContextCompat.getColor(view.getContext(), R.color.disabledInputColor);
        ObjectAnimator animator = null;
        if (tint) {
            animator = ObjectAnimator.ofObject(view,
                    "backgroundColor",
                    new ArgbEvaluator(),
                    color2Res,
                    colorRes);
        } else {
            animator = ObjectAnimator.ofObject(view,
                    "backgroundColor",
                    new ArgbEvaluator(),
                    colorRes,
                    color2Res);
        }

        animator.setDuration(BG_COLOR_ANIMATION_DURATION);
        animator.start();
    }

    private static void animateVerticalBias(View view, Float position) {
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) view.getLayoutParams();
        ValueAnimator animator = ValueAnimator.ofFloat(layoutParams.verticalBias, position);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ConstraintLayout.LayoutParams newParams = (ConstraintLayout.LayoutParams) view.getLayoutParams();
                Float animatedValue = (Float) animation.getAnimatedValue();
                newParams.verticalBias = animatedValue;
                view.requestLayout();
            }
        });

        animator.setInterpolator(new DecelerateInterpolator());
        animator.setDuration(VERTICAL_BIAS_ANIMATION_DURATION);
        animator.start();
    }
}